interface LogItem {
    id?: number;
    type: number;
    message: string;
    timestamp: number;
  }
  class LogIndexedDB {
    private static instance: LogIndexedDB; // 单例
    private db: IDBDatabase | null = null; // 数据库连接
    private dbName = 'LogDatabase'; // 数据库名称
    private storeName = 'logs'; // 存储名称
    private version = 1; // 版本
    private isInitializing = false; // 是否正在初始化
    private initPromise: Promise<void> | null = null; // 初始化Promise 
    private constructor() {}
    public static getInstance(): LogIndexedDB { // 获取单例
      if (!LogIndexedDB.instance) {
        LogIndexedDB.instance = new LogIndexedDB();
      }
      return LogIndexedDB.instance;
    }
    /**
     * 初始化数据库连接
     */
    public async init(): Promise<void> {
      if (this.db) {
        return Promise.resolve();
      }
      if (this.initPromise) {
        return this.initPromise;
      }
      this.initPromise = new Promise((resolve, reject) => {
        if (!window.indexedDB) {
          console.error('您的浏览器不支持IndexedDB');
          reject(new Error('浏览器不支持IndexedDB'));
          return;
        }
        // 打开数据库
        const request = window.indexedDB.open(this.dbName, this.version);
        // 错误处理
        request.onerror = (event) => {
          console.error('IndexedDB打开失败:', event);
          reject(new Error('IndexedDB打开失败'));
        };
        // 成功处理
        request.onsuccess = (event) => {
          this.db = (event.target as IDBOpenDBRequest).result;
          console.log('IndexedDB连接成功');
          resolve();
        };
        // 如果数据库不存在，则创建数据库,这个事件会先于数据库打开成功事件触发
        request.onupgradeneeded = (event) => {
          //获取数据库对象
          const db = (event.target as IDBOpenDBRequest).result;          
          // 创建日志存储对象
          if (!db.objectStoreNames.contains(this.storeName)) {
            const objectStore = db.createObjectStore(this.storeName, { 
              keyPath: 'id', 
              autoIncrement: true 
            });           
            // 创建索引用于快速查询
            objectStore.createIndex('type', 'type', { unique: false });
            objectStore.createIndex('timestamp', 'timestamp', { unique: false });
            objectStore.createIndex('type_timestamp', ['type', 'timestamp'], { unique: false });
          }
        };
      });
      return this.initPromise;
    }
  
    /**
     * 添加日志
     */
    public async addLog(type: number, message: string): Promise<number> {
      //是否初始化数据库,如果未初始化,则初始化数据库,如果已经初始化,则直接返回成功的promise
      await this.init();     
      //创建日志对象
      const logItem: LogItem = {
        type:Number(type),
        message,
        timestamp: Date.now()
      };
      return new Promise((resolve, reject) => {
        if (!this.db) {
          reject(new Error('数据库未初始化'));
          return;
        }
        //开始事务,进行读写操作,返回事务对象
        const transaction = this.db.transaction([this.storeName], 'readwrite');
        //通过事务对象获取存储对象
        const objectStore = transaction.objectStore(this.storeName);
        //添加日志,返回请求对象
        const request = objectStore.add(logItem);
        //添加成功触发回调
        request.onsuccess = (event) => {
          resolve((event.target as IDBRequest).result as number);
        };
        //添加失败触发回调
        request.onerror = (event) => {
          reject(new Error('添加日志失败'));
        };
      });
    }
  
    /**
     * 批量添加日志
     */
    public async addLogs(logs: { type: number; message: string }[]): Promise<void> {
      await this.init();
      return new Promise((resolve, reject) => {
        if (!this.db) {
          reject(new Error('数据库未初始化'));
          return;
        }
        //开始事务,进行读写操作
        const transaction = this.db.transaction([this.storeName], 'readwrite');
        const objectStore = transaction.objectStore(this.storeName);       
        logs.forEach(log => {
          const logItem: LogItem = {
            type: log.type,
            message: log.message,
            timestamp: Date.now()
          };
          objectStore.add(logItem);
        });
        transaction.oncomplete = () => {
          resolve();
        };
        transaction.onerror = () => {
          reject(new Error('批量添加日志失败'));
        };
      });
    }
  
    /**
     * 获取指定类型的日志
     */
    public async getLogsByType(type: number, limit: number = 1000): Promise<LogItem[]> {
      type = Number(type)
      await this.init();
      return new Promise((resolve, reject) => {
        if (!this.db) {
          reject(new Error('数据库未初始化'));
          return;
        }
        const transaction = this.db.transaction([this.storeName], 'readonly');
        const objectStore = transaction.objectStore(this.storeName);
        const index = objectStore.index('type');
        const range = IDBKeyRange.only(type);
        // 使用 prev 来获取最新的数据
        const request = index.openCursor(range, 'prev');
        const results: LogItem[] = [];        
        request.onsuccess = (event) => {
          const cursor = (event.target as IDBRequest).result as IDBCursorWithValue;
          if (cursor && results.length < limit) {
            results.push(cursor.value);
            cursor.continue();
          } else {
            // 返回最新的 limit 条数据
            resolve(results);
          }
        };
    
        request.onerror = () => {
          reject(new Error('获取日志失败'));
        };
      });
    }
  
    /**
     * 获取最近的日志（所有类型）
     */
    public async getRecentLogs(limit: number = 100): Promise<LogItem[]> {
      await this.init();  
      return new Promise((resolve, reject) => {
        if (!this.db) {
          reject(new Error('数据库未初始化'));
          return;
        }
        const transaction = this.db.transaction([this.storeName], 'readonly');
        const objectStore = transaction.objectStore(this.storeName);
        const index = objectStore.index('timestamp');
        const request = index.openCursor(null, 'prev'); // 按时间戳倒序  
        const results: LogItem[] = [];
        request.onsuccess = (event) => {
          const cursor = (event.target as IDBRequest).result as IDBCursorWithValue;          
          if (cursor && results.length < limit) {
            results.push(cursor.value);
            cursor.continue();
          } else {
            resolve(results);
          }
        };
        request.onerror = () => {
          reject(new Error('获取日志失败'));
        };
      });
    }
  
    /**
     * 清除特定类型的日志
     */
    public async clearLogsByType(type: number): Promise<void> {
      await this.init();
      return new Promise((resolve, reject) => {
        if (!this.db) {
          reject(new Error('数据库未初始化'));
          return;
        }
        const transaction = this.db.transaction([this.storeName], 'readwrite');
        const objectStore = transaction.objectStore(this.storeName);
        const index = objectStore.index('type');
        const range = IDBKeyRange.only(type);
        const request = index.openCursor(range);
        request.onsuccess = (event) => {
          const cursor = (event.target as IDBRequest).result as IDBCursorWithValue;
          if (cursor) {
            cursor.delete();
            cursor.continue();
          }
        };
        transaction.oncomplete = () => {
          resolve();
        };
        transaction.onerror = () => {
          reject(new Error('清除日志失败'));
        };
      });
    }
  
    /**
     * 清除指定日期前的日志
     */
    public async clearLogsBefore(timestamp: number): Promise<void> {
      await this.init();
      return new Promise((resolve, reject) => {
        if (!this.db) {
          reject(new Error('数据库未初始化'));
          return;
        }
        const transaction = this.db.transaction([this.storeName], 'readwrite');
        const objectStore = transaction.objectStore(this.storeName);
        const index = objectStore.index('timestamp');
        const range = IDBKeyRange.upperBound(timestamp);
        const request = index.openCursor(range);
        request.onsuccess = (event) => {
          const cursor = (event.target as IDBRequest).result as IDBCursorWithValue;
          if (cursor) {
            cursor.delete();
            cursor.continue();
          }
        };
        transaction.oncomplete = () => {
          resolve();
        };
        transaction.onerror = () => {
          reject(new Error('清除日志失败'));
        };
      });
    }
  
    /**
     * 清除所有日志
     */
    public async clearAllLogs(): Promise<void> {
      await this.init();
      return new Promise((resolve, reject) => {
        if (!this.db) {
          reject(new Error('数据库未初始化'));
          return;
        }
        const transaction = this.db.transaction([this.storeName], 'readwrite');
        const objectStore = transaction.objectStore(this.storeName);
        const request = objectStore.clear();
        
        request.onsuccess = () => {
          console.log('所有日志已清除');
          resolve();
        };
        
        request.onerror = () => {
          reject(new Error('清除所有日志失败'));
        };
      });
    }
  
    /**
     * 控制每种类型日志的数量上限
     */
    public async limitLogsCount(type: number, maxCount: number): Promise<void> {
      type = Number(type)
      const logs = await this.getLogsByType(type);
      if (logs.length <= maxCount) {
        return;
      }
      // 需要删除的是最旧的数据，即数组后面的部分
      const logsToDelete = logs.slice(maxCount);
      if (logsToDelete.length === 0) {
        return;
      }   
      await this.init();
      return new Promise((resolve, reject) => {
        if (!this.db) {
          reject(new Error('数据库未初始化'));
          return;
        }
        const transaction = this.db.transaction([this.storeName], 'readwrite');
        const objectStore = transaction.objectStore(this.storeName);
        // 删除最旧的数据
        logsToDelete.forEach(log => {
          if (log.id !== undefined) {
            objectStore.delete(log.id);
          }
        });
    
        // 提交事务
        transaction.oncomplete = () => {
          resolve();
        };
        transaction.onerror = () => {
          reject(new Error('限制日志数量失败'));
        };
      });
    }
  
    /**
     * 关闭数据库连接
     */
    public close(): void {
      if (this.db) {
        this.db.close();
        this.db = null;
        this.initPromise = null;
      }
    }
  }
  
  export default LogIndexedDB;